package com.wwdx.shiro;

import com.wwdx.utils.ConstantHolder;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import java.util.HashMap;
import java.util.Map;

/**
 * @author liguoliang
 * @date 2017-12-26
 */
public class ShiroHashedCredentialsMatcher extends HashedCredentialsMatcher {

    private RedisTemplate<String,Map<String,Object>> redisTemplate;

    public ShiroHashedCredentialsMatcher(RedisTemplate<String, Map<String, Object>> redisTemplate) {
        super();
        //设置加密算法
        super.setHashAlgorithmName(Md5Hash.ALGORITHM_NAME);
        //迭代次数,默认为1
        super.setHashIterations(GlobalStatic.HASHITERATIONS);
        this.redisTemplate = redisTemplate;
    }

	@Override
	public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
		//匹配结果
		boolean doCredentialsMatch = super.doCredentialsMatch(token, info);
		//处理密码错误缓存
		UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;

        String userName = usernamePasswordToken.getUsername();
        String key = String.format(ConstantHolder.USER_LOGIN,userName);
        //如果登录成功
		if(doCredentialsMatch){
            redisTemplate.delete(key);
		}else{
            ValueOperations<String, Map<String,Object>> valueOperations = redisTemplate.opsForValue();
            Map<String,Object> map = valueOperations.get(key);
            Integer errorLogincount = 1;
            if (map == null){
                map = new HashMap<>(2);
            }else {
                errorLogincount = Integer.valueOf(map.get("errorcount").toString());
            }
            String errorMessage = "密码错误!剩余" + (GlobalStatic.ERROR_LOGIN_COUNT - errorLogincount) + "次输入机会";
            errorLogincount ++;
            map.put("errorcount",errorLogincount);
            map.put("time",0);
            valueOperations.set(key, map);
            throw new IncorrectCredentialsException(errorMessage);
		}
		return true;
	}
}